import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;

/**
 * This class is used to manage the books and magazines. It supports following functions:
 * 
 * 1. read all data from the given csv files in the folder "data" (method names: readAuthors(), readBooks(),
 * readMagazines()). After reading the files we will use method analyseAuthorFiles() to determine which author has which
 * books/magazins.
 * 
 * 2. show all books/magazines with the details (method name: printFiles())
 * 
 * 3. search and show a book/magazine according to isbn number (method name: getFile())
 * 
 * 4. search and show all books/magazines of an author (method name: filesWritenBy())
 * 
 * 5. sort and show all books/magazines by the title (method name: sortByTitle())
 * 
 * @author Xi Luo
 * 
 */
public class BookManagement {

   // author list from csv data
   public List<Author> authors = new ArrayList<Author>();
   // file list for books/magazines from csv data
   public List<File> files = new ArrayList<File>();

   /**
    * @param args
    */
   public static void main(String[] args) {
      BookManagement bookManagement = new BookManagement();
      // read the *.csv files
      bookManagement.readAuthors("data/autoren.csv");
      bookManagement.readBooks("data/buecher.csv");
      bookManagement.readMagazines("data/zeitschriften.csv");

      // analyze the relationships between authors and files (books/magazines)
      bookManagement.analyseAuthorFiles(bookManagement.authors, bookManagement.files);

      // show all books/magazines from the *.csv files
      bookManagement.printFiles(bookManagement.files);

      // get book/magazine according to the isbn number
      System.out.println("The given book isbn is: " + "554-5545-4518.");
      File book = bookManagement.getFile("5554-5545-4518");
      bookManagement.printFile(book);

      // get all books/magazins of an author
      List<File> filesOfAuthor = bookManagement.filesWritenBy("pr-walter@optivo.de");
      System.out.println("The books/magazines from the author:");
      bookManagement.printFiles(filesOfAuthor);

      // sort books/magazines by the title
      bookManagement.sortByTitle(bookManagement.files);
      bookManagement.printFiles(bookManagement.files);
   }

   /**
    * Read the authors.cvs file for loading the authors.
    * 
    * @param fileName path of the authors.cvs file
    */
   public void readAuthors(String fileName) {
      String csvFile = fileName;
      BufferedReader br = null;
      String line = "";
      // use semicolon as separator
      String cvsSplitBy = ";";

      // read authors
      try {
         br = new BufferedReader(new FileReader(csvFile));
         line = br.readLine();

         while ((line = br.readLine()) != null) {
            // the information of the book
            String[] authorInfo = line.split(cvsSplitBy);
            // add the author into the author list of the book manageemnt
            authors.add(new Author(authorInfo[0], authorInfo[1], authorInfo[2]));
         }
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      finally {
         if (br != null) {
            try {
               br.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
      System.out.println("read authors.cvs is done!");
   }

   /**
    * Read the books.cvs file for loading the books.
    * 
    * @param fileName path of the books.cvs file
    */
   public void readBooks(String fileName) {
      String csvFile = fileName;
      BufferedReader br = null;
      String line = "";
      // use semicolon as separator
      String cvsSplitBy = ";";

      // read books
      try {
         br = new BufferedReader(new FileReader(csvFile));
         line = br.readLine();

         while ((line = br.readLine()) != null) {
            // the information of the book
            String[] bookInfo = line.split(cvsSplitBy);
            // create a new book
            Book book = new Book(bookInfo[0], bookInfo[1], bookInfo[2], bookInfo[3]);
            // add the book into the file list of the book management
            files.add(book);
         }
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      finally {
         if (br != null) {
            try {
               br.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
      System.out.println("read books.cvs is done!");
   }

   /**
    * Read the magazines.cvs file for loading the magazines.
    * 
    * @param fileName path of the magazine.cvs file
    */
   public void readMagazines(String fileName) {
      String csvFile = fileName;
      BufferedReader br = null;
      String line = "";
      // use semicolon as separator
      String cvsSplitBy = ";";

      // read magazines
      try {
         br = new BufferedReader(new FileReader(csvFile));
         line = br.readLine();

         while ((line = br.readLine()) != null) {
            // the information of the magazine
            String[] magazineInfo = line.split(cvsSplitBy);
            // create a new magazine
            Magazine magazine = new Magazine(magazineInfo[0], magazineInfo[1], magazineInfo[2], magazineInfo[3]);
            // add the magazine into the file list of the book management
            files.add(magazine);
         }
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      finally {
         if (br != null) {
            try {
               br.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
      System.out.println("read magazines.cvs is done!");
   }

   /**
    * Analyze the relationship between the author list and file list. This methode can determine that which author has
    * which books/magazines.
    * 
    * @param authors author list
    * @param files file list
    */
   public void analyseAuthorFiles(List<Author> authors, List<File> files) {

      // use comma as separator
      String authorSplitBy = ",";

      for (File file : files) {
         // the information of authors of the book/magazine
         String[] authorsInfo = file.getAuthorString().split(authorSplitBy);
         // the authors of the book/magazine
         List<Author> fileAuthors = new ArrayList<Author>();

         // search the authors from the author list for the book
         for (String authorEmail : authorsInfo) {
            for (Author author : authors) {
               if (authorEmail.equals(author.getEmail())) {
                  fileAuthors.add(author);
               }
            }
         }
         // set the author lists for the file;
         file.setAuthors(fileAuthors);
         // the authors have the file
         for (Author author : fileAuthors) {
            author.getFiles().add(file);
         }
      }
   }

   /**
    * Show all books/magazines in the book list.
    * 
    * @param files
    */
   public void printFiles(List<File> files) {
      System.out.println("The details of the books/magazines:");
      for (File file : files) {
         printFile(file);
      }
   }

   /**
    * Print the given file.
    * 
    * @param file
    */
   public void printFile(File file) {
      String result = file.getTitle() + " ; "; // file title
      result += file.getIsbn() + " ; "; // file isbn
      for (Author author : file.getAuthors()) {
         result += author.getEmail() + " , "; // authors of the file
      }
      result = result.substring(0, result.length() - 3); // delete the last " , "
      if (file.getClass().equals(Book.class)) {
         result += " ; " + ((Book) file).getShortDescription(); // file short description
      } else {
         result += " ; " + ((Magazine) file).getPublicDate(); // file publication date
      }
      System.out.println(result);
      System.out.println("");
   }

   /**
    * Check if the given author is contained in the author list of the book management.
    * 
    * @param id id can be email, first name of last name of the given author
    * @return
    */
   public boolean containsAuthor(String id) {
      for (Author author : authors) {
         if (id.equals(author.getEmail()) || id.equals(author.getFirstName()) || id.equals(author.getLastName())) {
            return true;
         }
      }
      return false;
   }

   /**
    * Return the author according to the given author id.
    * 
    * @param id id can be email, first name of last name of the given author
    * @return
    */
   public Author getAuthor(String id) {
      for (Author author : authors) {
         if (id.equals(author.getEmail()) || id.equals(author.getFirstName()) || id.equals(author.getLastName())) {
            return author;
         }
      }
      return null;
   }

   /**
    * Check if the given book/magazine is contained in the file list of the book management.
    * 
    * @param id id can be isbn number or title of book/magazine
    * @return
    */
   public boolean containsFile(String id) {
      for (File file : files) {
         if (id.equals(file.getIsbn()) || id.equals(file.getTitle())) {
            return true;
         }
      }
      return false;
   }

   /**
    * Return the file according to the given file id.
    * 
    * @param id id can be isbn number or title of book/magazine
    * @return
    */
   public File getFile(String id) {
      for (File file : files) {
         if (id.equals(file.getIsbn()) || id.equals(file.getTitle())) {
            return file;
         }
      }
      return null;
   }

   /**
    * Return books/magazines of the given author
    * 
    * @param id id can be email, first name of last name of the given author
    * @return
    */
   public List<File> filesWritenBy(String id) {
      Author author = getAuthor(id);
      return author.getFiles();
   }

   /**
    * Sort books/magazines by the title.
    * 
    * @param files
    */
   public void sortByTitle(List<File> files) {
      // create a comparator for the sorting
      Comparator<File> sortByTitle = new Comparator<File>() {

         @Override
         public int compare(File b1, File b2) {
            return b1.getTitle().compareTo(b2.getTitle());
         }
      };
      Collections.sort(files, sortByTitle);
   }
}
